#!/bin/sh
##
#   Quick analyze of core or pid thru GDB
# Author: Andrey Zakharov ( aazaharov81( ).at.( )gmail(.dot.)com, vaulter( ).at.( )nm(.dot.)ru )
# 2009-04-17
# 2009-06-17 Improved bunch mode
# 2010-03-17 Added handling of pid's
#
#

ID='$Id$'

usage()
{
    echo "$0 <corefiles|corefile|pid>"
}

[ -z "$1" ] && usage && exit 1

# globals:
BIN=
BINDIR=
REASON=
nTHREADS=

##
# Get threads info from running proc
#
# @param $1 dir
# @param $2 bin
# @param $3 core | pid
# @return nothing
# @output gdb output
infothreads() 
{
	( 
		if is_integer $3; then
			gdb -cd="$1" -nx -quiet -batch -command=/dev/stdin "$2" "$3"
		else
			gdb -cd="$1" -nx -quiet -batch -command=/dev/stdin "$2" -c "$3"
		fi )<<CMD
	info threads
CMD
}

##
# Count threads in gdb output
# @param $1 - gdb output
countthreads()
{
	echo "$1" | grep -E '*? [0-9]+ (Thread|process)' -c
}
##
# Retrieve first available info
# binary, reason of core and num of threads
# @param $1 - core | pid
getfirstinfo()
{
	local atfirst;
	
	if is_integer $1; then #read doesn't works :(
		if [ -r "/proc/$1/cmdline" ]; then
			bin=$( awk '{ print $1 }' /proc/$1/cmdline )
			eval "$( cat /proc/$1/environ  | tr "\000" "\n" | grep LD_LIBRARY_PATH )"
			BINDIR="$( readlink -f /proc/$1/cwd )"
			atfirst="$( infothreads "$BINDIR" "$bin" "$1" )"
		else
			echo $1 not valid process PID?
		fi
	else
		atfirst="$( gdb -nx -quiet -batch -c "$1" )"
		local bin="$( echo "$atfirst" | grep "Core was generated by" | awk '{ print $5 }')"
		bin="${bin#\`}"
		BINDIR="$( dirname "$bin" )"
		REASON="$( echo "$atfirst" | grep "Program terminated with signal" | awk '{ print $5 $6 $7 }')"
		atfirst="$( infothreads "$BINDIR" "$bin" "$1" )"
	fi

	nTHREADS="$( countthreads "$atfirst" )"
	echo "BIN: $bin with $nTHREADS threads"
	BIN="$bin" #global

}

##
# Prints backtraces of all threads
where()
{
	local corefile="$1"
	
	if ! is_integer $1; then
		corefile="$( readlink -f "$1" )"
	fi
		
    getfirstinfo "$corefile"
    
    cmds=$( for nt in $(seq 1 $nTHREADS); do
      echo "thread $nt"
	  echo "echo \n======== Backtrace of thread #$nt ========\n"
	  echo "echo "
      echo "where"
    done )
	gdb -cd="$BINDIR" -n -quiet -batch -se="$BIN" -x /dev/stdin "$BIN" "$corefile" <<CMDS
	$cmds
CMDS

    #if echo "$REASON" | grep "6, Aborted." > /dev/null; then
    # just core from aborted by stopping routine....
    # need notify that current timeout is wrong or service was in deadlock?
    #    echo "#[ II ] Just from Aborted `basename $BIN`"
    #    echo -n "#[ ?? ] Sweeping...";    rm -v -i "$1"
    #else
        return $?
    #fi
}

##
# Checks for integer
function is_integer() {
    printf "%d" $1 > /dev/null 2>&1
    return $?
}

if [ 1 -eq $# ]; then
  mode=${mode:-1}
  #numthread "$1"
  where "$1"
  
else ## bunch of core...
  #kdialog --yesno "Show about every file sep. info". TODO... atree
  mode=${mode:-2}

  for c in $@; do
    echo -n -e "$c\t"
    dump="$(gdb -nx -quiet -batch -core="$c")"
    ds="$(echo "$dump" | head --lines=1)"
    echo -n -e "$ds\t"
    echo "$dump\t" | grep "Program terminated with signal" | awk '{ print $5 $6 $7 }'
    
    #where "$c"
    
  done

fi